/** @file    EncoderProtocolRaw.cpp
 *  @author  Alessandro Polo
 *  @version $Id: EncoderProtocolRaw.cpp 2821 2010-08-01 11:44:26Z alex $
 *  @brief
 * File containing basic implementation of wosh::persistence::EncoderProtocolRaw.
 * The header for this class can be found in EncoderProtocolRaw.h, check that file
 * for class description.
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/
 
 #include <framework/persistence/raw/EncoderProtocolRaw.h>

 #include <core/ObjectFactory.h>
 #include <core/FileSystem.h>
 #include <core/SystemError.h>


using namespace std;
namespace wosh {
 namespace persistence {
  namespace raw {

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
 WOSH_REGISTER(wosh::persistence::raw::EncoderProtocolRaw, "wosh::EncoderProtocol", 1.01, _static_EncoderProtocolRaw )

EncoderProtocolRaw::EncoderProtocolRaw()
	: EncoderProtocol() {
	Object::setName("EncoderProtocolRaw" );
	Object::getURI().setName( Object::getName() );
	Log.setContext( Object::getName() );
 }

PersistenceDb* EncoderProtocolRaw::createDb() const {
	PersistenceDbRaw* db = new PersistenceDbRaw();
	return db;
 }

WRESULT EncoderProtocolRaw::saveObject( const ISerializable* object, const std::string& parameters ) {
	if ( object == NULL ) return WRET_ERR_PARAM;
	(void)parameters;
	/*
	getEncodersBase().transactionBeginRead();
	EncoderBase* enc = selectEncoder_(getEncodersBase(), object->getClassName());
	if ( enc == NULL ) {
		getEncodersBase().transactionEnd();
		return WRET_ERR_ILLEGAL_USE;
	 }
	*/
	WRESULT ret = WRET_ERR_INTERNAL;
	//enc->serializeTo(object, 
//	getEncodersBase().transactionEnd();

	return ret;
 }

WRESULT EncoderProtocolRaw::saveObjects( const std::vector<ISerializable*>& objects, const std::string& parameters ) {
	std::string filename = parameters;
	FilePath xmlFile;
	if ( !xmlFile.set( filename ) ) {
		Log(LOG_CRITICAL, ":saveObjects() FAILED resolving of %s", filename.c_str() );
		return WRET_ERR_PARAM;
	 }
	WRESULT ret = WRET_OK;
	Log(LOG_VERBOSE, ":saveObjects() saving %d items in %s", objects.size(), xmlFile.getPathLocal().c_str() );
	FILE* fout = fopen (xmlFile.getPathLocal().c_str(), "w");
	if ( fout == NULL ) {
		wosh::SystemError::raise(this, Log, SystemError::CRITICAL, 0, "saveObjects", "FAILED#1 : Cannot write to file %s", xmlFile.getPathLocal().c_str() );
		return WRET_ERR_ILLEGAL_USE;
	 }
	// write FILE HEADER
	char* bufHeader = new char[255];
	memset(bufHeader, 0, 255);
	// setAttribute("encoder-class", getClassName() );
	// setAttribute("encoder-protocol", getProtocol() );
	// setAttribute("encoder-version", QString::number(getProtocolVersion()) );
	fwrite( bufHeader, 1, 254, fout );
	delete [] bufHeader;

	std::vector<std::string> classErrs;
	int j = 0;
	std::vector<ISerializable*>::const_iterator it;
	for ( it=objects.begin(); it != objects.end(); ++it, ++j ) {
		if ( *it == NULL ) continue;
		EncoderBaseRaw* enc = dynamic_cast<EncoderBaseRaw*>( getEncoderFor_((*it)->getClassName()) );
		if ( enc == NULL ) {
			classErrs.push_back((*it)->getClassName());
			Log(LOG_CRITICAL, ":saveObjects() Node#%d : Class not found '%s'", j, (*it)->getClassName() );
			continue;
		 }

		WRESULT ret = enc->serializeTo( *it, fout, false );
		if ( WFAILED(ret) )
			Log(LOG_WARNING, ":saveObjects() Node#%d : %s Error ret=%d", j, (*it)->getClassName(), ret );
		else
			Log(LOG_VERBOSE, ":saveObjects() Node#%d : saved.", j );
	 }
	fclose(fout);

	if ( !classErrs.empty() ) {
		std::string errs = wosh::Utilities::joinVector(classErrs, "; ");
		SystemError::raise(this, Log, SystemError::CRITICAL, 0, "saveObjects", "%d ERRORS: Classes not found: %s", classErrs.size(), errs.c_str() );
		ret = WRET_ERR_INTERNAL;
	 }
	return ret;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT EncoderProtocolRaw::loadObjects( std::vector<ISerializable*>& objects, const std::string& parameters ) {
	FilePath xmlFile;
	std::string source_archive = parameters;
	if ( !xmlFile.set( source_archive ) ) {
		Log(LOG_CRITICAL, ":loadObjects() FAILED resolving of %s", source_archive.c_str() );
		return WRET_ERR_PARAM;
	 }
	std::vector<std::string> sourceFiles;
	if ( xmlFile.isFolder() ) {
		WRESULT ret = FileSystem::getFilesOf( xmlFile.getPathLocal(), sourceFiles, true, true, ".xml" );
		if ( WFAILED(ret) || sourceFiles.empty() ) {
			Log(LOG_CRITICAL, ":loadObjects() FAILED getting files of %s", xmlFile.getPathLocal().c_str() );
			return WRET_ERR_PARAM;
		 }
		Log(LOG_VERBOSE, ":loadObjects() parsing %d files of folder %s", sourceFiles.size(), xmlFile.getPathLocal().c_str() );
	 }
	else if ( xmlFile.isFile() ) {
		sourceFiles.push_back( xmlFile.getPathLocal() );
	 }
	else {
		Log(LOG_CRITICAL, ":loadObjects() FAILED file %s doesn't exist!", xmlFile.getPathLocal().c_str() );
		return WRET_ERR_PARAM;
	 }

	std::string filename;
	std::vector<std::string>::iterator it;
	for ( it=sourceFiles.begin(); it!=sourceFiles.end(); ++it ) {
		filename = *it;

		FILE* fin = fopen (xmlFile.getPathLocal().c_str(), "r");
		if ( fin == NULL ) {
			wosh::SystemError::raise(this, Log, SystemError::CRITICAL, 0, "saveObjects", "FAILED#1 : Cannot read to file %s", xmlFile.getPathLocal().c_str() );
			return WRET_ERR_ILLEGAL_USE;
		 }

		fclose(fin);

	 }

	return WRET_OK;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

WRESULT EncoderProtocolRaw::serializeTo( const ISerializable* object, FILE* fout, int encoder_options ) {
	if ( object == NULL || fout == NULL ) return WRET_ERR_PARAM;
	getEncoders().transactionBeginRead();
	EncoderBaseRaw* enc = dynamic_cast<EncoderBaseRaw*>( getEncoderFor_(object->getClassName()) );
	if ( enc == NULL ) {
		printf("\nEncoderProtocolRaw::serializeTo(%s) missing!\n",object->getClassName() );
		getEncoders().transactionEnd();
		return WRET_ERR_ILLEGAL_USE;
	 }
//	contNode.setAttribute("class", QString(object->getClassName()) );
//	if ( !EncoderBase::isCompact(encoder_options) )
//		contNode.setAttribute("encoder", QString(enc->getClassName()) );
	WRESULT ret = enc->serializeTo(object, fout, encoder_options);
	getEncoders().transactionEnd();
	return ret;
 }

WRESULT EncoderProtocolRaw::deserializeFrom( ISerializable* object, FILE* fin ) {
	if ( object == NULL || fin == NULL ) return WRET_ERR_PARAM;
	getEncoders().transactionBeginRead();
	EncoderBaseRaw* enc = dynamic_cast<EncoderBaseRaw*>( getEncoderFor_(object->getClassName()) );
	if ( enc == NULL ) {
		printf("\nEncoderProtocolRaw::deserializeFrom(%s) missing!\n",object->getClassName() );
		getEncoders().transactionEnd();
		return WRET_ERR_ILLEGAL_USE;
	 }
	WRESULT ret = enc->deserializeFrom(object, fin);
	getEncoders().transactionEnd();
	return ret;
 }
	
ISerializable* EncoderProtocolRaw::deserializeFrom( FILE* fin, WRESULT* return_code ) {
	std::string classname = ""; double version = 0.0;
//	if ( contNode.hasAttribute("class") )
//		classname = contNode.attribute("class").toLatin1().data();
	getEncoders().transactionBeginRead();
	EncoderBaseRaw* enc = dynamic_cast<EncoderBaseRaw*>( getEncoderFor_(classname.c_str()) );
	if ( enc == NULL ) {
		if ( return_code != NULL ) *return_code = WRET_ERR_PARAM;
		getEncoders().transactionEnd();
		return NULL;
	 }
	ISerializable* object = ObjectFactory::createTypeOf<ISerializable>(classname, version);
	if ( object == NULL ) {
		if ( return_code != NULL ) *return_code = WRET_ERR_ILLEGAL_USE;
		getEncoders().transactionEnd();
		return NULL;
	 }
	WRESULT ret = enc->deserializeFrom(object, fin);
	getEncoders().transactionEnd();
	if ( return_code != NULL ) *return_code = ret;
	return object;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_REGISTER_INTERFACE(wosh::persistence::raw::EncoderBaseRaw, "wosh::EncoderBase", 1.01, _static_EncoderBaseRaw )

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

int64 EncoderBaseRaw::serializeTo( const ISerializable* object, char* output, int64 buffer_size, int encoder_options ) {
	return 0;
 }

int64 EncoderBaseRaw::deserializeFrom( ISerializable* object, const char* buffer, int64 buffer_size ) {
	WRESULT ret = WRET_ERR_INTERNAL;

	return 0;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

 WOSH_REGISTER(wosh::persistence::raw::PersistenceDbRaw, "wosh::PersistenceDb", 1.01, _static_PersistenceDbRaw )

WRESULT PersistenceDbRaw::save() const {
	return WRET_ERR_INTERNAL;
 }
WRESULT PersistenceDbRaw::load() {
	return WRET_ERR_INTERNAL;
 }

//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////

  }; // namespace raw
 }; // namespace persistence
}; // namespace wosh
